<script setup lang="ts">
import { computed, nextTick, onMounted, ref, unref } from 'vue';
import type { DrawerPlacement, FormInst, FormItemInst, FormItemRule, FormRules } from 'naive-ui';
import { useMessage } from 'naive-ui';
import { createUser, getRouteList, updateUser } from '@/service/api';

interface ModelType {
  username: string | null;
  password: string | null;
  reenteredPassword: string | null;
  roleIds: number[];
}

defineOptions({
  name: 'UserDrawer'
});

const active = ref(false);
const placement = ref<DrawerPlacement>('right');
const title = ref('用户');
const id = ref(0);
const loading = ref(false);
const message = useMessage();

const formRef = ref<FormInst | null>(null);
const rPasswordFormItemRef = ref<FormItemInst | null>(null);
const modelRef = ref<ModelType>({
  username: '',
  password: null,
  reenteredPassword: null,
  roleIds: []
});
const options = ref<
  {
    label: string;
    value: number;
  }[]
>([]);

const rules = computed<FormRules>(() => {
  const i = unref(id);
  return {
    username: [
      {
        required: true,
        validator(_rule: FormItemRule, value: string) {
          if (!value) {
            return new Error('需要用户名');
          }
          return true;
        },
        trigger: ['input', 'blur']
      }
    ],
    password: [
      {
        required: i === 0,
        message: '请输入密码'
      }
    ],
    reenteredPassword:
      i === 0
        ? [
            {
              required: i === 0,
              message: '请再次输入密码',
              trigger: ['input', 'blur']
            },
            {
              validator: validatePasswordStartWith,
              message: '两次密码输入不一致',
              trigger: 'input'
            },
            {
              validator: validatePasswordSame,
              message: '两次密码输入不一致',
              trigger: ['blur', 'password-input']
            }
          ]
        : [],
    roleIds: [
      {
        required: true,
        message: '请选择角色'
      }
    ]
  };
});

const emit = defineEmits<{
  (e: 'afterLeave'): void;
}>();

function openDrawer(value: Partial<ModelType> & { title: string; id?: number }) {
  const { title: t, id: i, ...rest } = value;
  title.value = `${t}用户`;
  id.value = i || 0;
  active.value = true;
  nextTick(() => {
    modelRef.value = {
      ...modelRef.value,
      ...rest
    };
  });
}

function validatePasswordStartWith(_rule: FormItemRule, value: string): boolean {
  return (
    Boolean(modelRef.value.password) &&
    modelRef.value.password !== null &&
    modelRef.value.password.startsWith(value) &&
    modelRef.value.password.length >= value.length
  );
}
function validatePasswordSame(_rule: FormItemRule, value: string): boolean {
  return value === modelRef.value.password;
}

function handlePasswordInput() {
  if (modelRef.value.reenteredPassword) {
    rPasswordFormItemRef.value?.validate({ trigger: 'password-input' });
  }
}

function handleValidateButtonClick(e: MouseEvent) {
  e.preventDefault();
  formRef.value?.validate(async errors => {
    if (!errors) {
      loading.value = true;
      const { roleIds, username, password } = modelRef.value;
      const cb = (value: any) => {
        loading.value = false;
        const { data, error } = value;
        if (error) {
          message.error(error.message);
          return;
        }
        afterLeave();
        emit('afterLeave');
        message.success(data);
      };
      if (id.value === 0) {
        if (!password || !username) {
          message.error('用户名或密码不能为空');
          loading.value = false;
          return;
        }
        const res = await createUser({
          username,
          password,
          roleIds
        });
        cb(res);
      } else {
        const res = await updateUser({
          id: id.value,
          username: username || undefined,
          password: password || undefined,
          roleIds
        });
        cb(res);
      }
      // message.success('验证成功');
    } else {
      message.error('验证失败');
    }
  });
}

function afterLeave() {
  active.value = false;
}

onMounted(async () => {
  const { data, error } = await getRouteList({ current: 1, size: 99 });
  if (error) {
    return;
  }

  options.value = data.records.map(item => ({
    label: item.name,
    value: item.id
  }));
});

defineExpose({
  openDrawer
});
</script>

<template>
  <NDrawer v-model:show="active" :width="402" :placement="placement">
    <NDrawerContent :title="title">
      <NForm ref="formRef" :model="modelRef" :rules="rules">
        <NFormItem path="username" label="用户名">
          <NInput v-model:value="modelRef.username" @keydown.enter.prevent />
        </NFormItem>
        <NFormItem path="password" label="密码">
          <NInput
            v-model:value="modelRef.password"
            type="password"
            @input="handlePasswordInput"
            @keydown.enter.prevent
          />
        </NFormItem>
        <NFormItem ref="rPasswordFormItemRef" first path="reenteredPassword" label="重复密码">
          <NInput
            v-model:value="modelRef.reenteredPassword"
            :disabled="!modelRef.password"
            type="password"
            @keydown.enter.prevent
          />
        </NFormItem>
        <NFormItem ref="rPasswordFormItemRef" first path="roleIds" label="角色">
          <NSelect v-model:value="modelRef.roleIds" multiple :options="options" />
        </NFormItem>
      </NForm>
      <template #footer>
        <NButton class="mr-2" ghost @click="afterLeave">取消</NButton>
        <NButton
          :disabled="modelRef.username === null"
          :loading="loading"
          ghost
          type="primary"
          @click="handleValidateButtonClick"
        >
          确定
        </NButton>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>

<style scoped></style>
